今天要介紹的部分,是整個天氣 App 的最後一塊拼圖 —— 自訂的 TableViewCell:SecondTableViewCell。
這個 Cell 的任務,是在第二個畫面中(SecondViewController)負責顯示每一個時間段的天氣資料,包括溫度、天氣狀況與舒適度等。
這個畫面的設計主要是以 XIB 完成的。
我們建立一個新的 SecondTableViewCell.xib,並加上以下元件:
完成後,記得設定 XIB 的 Class 為 SecondTableViewCell,並建立 IBOutlet 連線。
//
//  SecondTableViewCell.swift
//  Weather API
//
//  Created by imac-2156 on 2025/7/30.
//
import UIKit
// 自訂 TableViewCell,用來顯示單一時間段的天氣資料
class SecondTableViewCell: UITableViewCell {
    // MARK: - IBOutlet(UI 元件連接)
    @IBOutlet weak var lbClock: UILabel!       // 顯示時間
    @IBOutlet weak var lbPerson: UILabel!      // 顯示舒適度
    @IBOutlet weak var lbTempHigh: UILabel!    // 顯示最高溫
    @IBOutlet weak var lbTempLow: UILabel!     // 顯示最低溫
    @IBOutlet weak var lbCloud: UILabel!       // 顯示天氣狀況(晴、多雲、雨等)
    // 圖示 UI
    @IBOutlet weak var iconCloud: UIImageView!
    @IBOutlet weak var iconClock: UIImageView!
    @IBOutlet weak var iconPerson: UIImageView!
    @IBOutlet weak var iconTempHigh: UIImageView!
    @IBOutlet weak var iconTempLow: UIImageView!
    override func awakeFromNib() {
        super.awakeFromNib()
    }
    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }
configure() 方法這是 Cell 最核心的部分,用來接收從 API 回來的天氣資料並顯示。
    func configure(with weatherData: WeatherData, index: Int) {
        guard let location = weatherData.records.location.first else {
            重設標籤()
            return
        }
        func 尋找元素(名稱: String) -> WeatherElement? {
            return location.weatherElement.first { $0.elementName == 名稱 }
        }
        // 天氣狀況(Wx)
        if let wx = 尋找元素(名稱: "Wx")?.time.安全取得(索引: index) {
            lbCloud.text = wx.parameter.parameterName
            lbClock.text = wx.startTime
        } else {
            lbCloud.text = "-"
            lbClock.text = "-"
        }
        // 最低溫(MinT)
        if let minT = 尋找元素(名稱: "MinT")?.time.安全取得(索引: index) {
            lbTempLow.text = "\(minT.parameter.parameterName)°C"
        } else {
            lbTempLow.text = "-"
        }
        // 最高溫(MaxT)
        if let maxT = 尋找元素(名稱: "MaxT")?.time.安全取得(索引: index) {
            lbTempHigh.text = "\(maxT.parameter.parameterName)°C"
        } else {
            lbTempHigh.text = "-"
        }
        // 舒適度(CI)
        if let ci = 尋找元素(名稱: "CI")?.time.安全取得(索引: index) {
            lbPerson.text = ci.parameter.parameterName
        } else {
            lbPerson.text = "-"
        }
    }
這裡的 尋找元素(名稱:) 是個小巧的內部函數,
用來快速根據氣象資料中的名稱(例如 "Wx", "MinT", "MaxT", "CI")找到對應的項目。
為了避免因索引越界造成的崩潰,我們額外擴充了陣列安全存取功能:
extension Array {
    func 安全取得(索引: Int) -> Element? {
        return indices.contains(索引) ? self[索引] : nil
    }
}
這樣當資料不足或 API 回傳異常時,就能安全地顯示「-」而不會造成應用程式閃退。
為了確保當資料載入錯誤時仍有預設畫面:
private func 重設標籤() {
    lbCloud.text = "-"
    lbClock.text = "-"
    lbTempLow.text = "-"
    lbTempHigh.text = "-"
    lbPerson.text = "-"
}
到這裡,我們的天氣 App 已經完成了完整流程:
這個 Cell 的實作重點在於「資料解析的結構化」與「介面綁定的清晰性」,
讓每筆氣象資料都能以一致格式呈現,整體架構清楚易懂。